package NWish
{
	import NWish.Interface.IApp;
	import NWish.Interface.ILogger;
	
	import away3d.cameras.Camera3D;
	import away3d.containers.ObjectContainer3D;
	import away3d.containers.Scene3D;
	import away3d.containers.View3D;
	import away3d.debug.AwayStats;
	import away3d.entities.Entity;
	import away3d.lights.LightBase;
	import away3d.primitives.SkyBox;
	
	import flash.display.Sprite;
	import flash.display.StageAlign;
	import flash.display.StageScaleMode;
	import flash.events.Event;
	
	
	//todo ...
	//多个view
	public class Away3d extends Sprite
	{
		static public const SystemCamera = '@SysCamera';
		static public const SysIcon3d = '@SysIcon3d';
		static public const SysIcon3d1 = '@Sys';
		
		
		private var _app:IApp;
		private var _view : View3D;
		
		private var _lights:Array = [];
		
		public function Away3d(parent:IApp)
		{
			super();
			parent.rootSprite.addChild(this);
			
			
			_app = parent;
			
			_app.rootSprite.addEventListener(Event.ENTER_FRAME, _handleEnterFrame);
			
			//
			//_app.rootSprite.stage.scaleMode = StageScaleMode.NO_SCALE;
			//_app.rootSprite.stage.align = StageAlign.TOP_LEFT;
			_app.rootSprite.stage.addEventListener(Event.RESIZE, _onStageResize);
			
			
			//
			_app.NWEventDispatcher.addEventListener(NWEvent.CLEAR_SCENE,onClearScene);
			_app.NWEventDispatcher.addEventListener(NWEvent.NEW_SCENE,onNewScene);
			_app.NWEventDispatcher.addEventListener(NWEvent.CREATE_OBJECT,onCreateObject);
			_app.NWEventDispatcher.addEventListener(NWEvent.DELETE_OBJECT,onDeleteObject);
			_app.NWEventDispatcher.addEventListener(NWEvent.SELSCT_OBJECT,onSelectObject);
			
			
			//
			//_view.scene.addChild(_view.camera);
			
			
			//
			_app.rootSprite.addChild(new AwayStats());
		}
		
		public function init()
		{
			//
			var menuBar:MenuBar = _app.getPlugin('MenuBar') as MenuBar;
			
			if(menuBar)
				menuBar.windowMenu.addMenuItem("&Stats").addActionListener(_showWindow);
			
		}
		
		private function _showWindow(e)
		{
			if(AwayStats.instance)
				AwayStats.instance.visible = !AwayStats.instance.visible;
		}
		
		private function _onStageResize(event :Event) : void
		{
			if(_view)
			{
				if(_view.width != _app.stageWidth)
					_view.width = _app.stageWidth;
				
				if(_view.height != _app.stageHeight)
					_view.height = _app.stageHeight;
			}
		}
		
		
		private function _handleEnterFrame(ev : Event) : void
		{
			if(_view)
				_view.render();
		}
		
		
		public function addView3D(v:View3D)
		{
			if(_view)
			{
				ILogger.log('can not create tow View3D, todo implement multi view!');
				return;
				//throw new Error();
			}
				
			_view = v;
			_view.width = _app.stageWidth;
			_view.height = _app.stageHeight;
			
			this.addChild(v);
			
			if(AwayStats.instance)
				AwayStats.instance.registerView(v);
		}
		
		public function removeView3D(v:View3D)
		{
			if(_view == v)
			{
				if(AwayStats.instance)
					AwayStats.instance.unregisterView(v);
				this.removeChild(_view);
				_view = null
			}
			else
			{
				throw new Error();
			}
		}
		
		public function get view() : View3D
		{
			return _view;
		}
		
		public function get scene() : Scene3D
		{
			if(_view)
				return _view.scene;
			
			return null;
		}
		
		public function get camera():Camera3D
		{
			if(_view)
				return _view.camera;
			return null;
		}
		
		public function get lights() : Array
		{
			if(_lights.length == 0)
				return null;
			
			return _lights;
		}
		
		private function onCreateObject(e:NWEvent)
		{
			var objs = e.objects;
			if(objs is Array == false)
				objs = [objs];
			
			for each(var o in objs)
			{
				if(o is View3D)
					addView3D(o);
				else if(o is LightBase)
					_lights.push(o)
			}
		}
		
		
		private var _gcObjects:Array = [];
		private function onDeleteObject(e:NWEvent)
		{
			if(e.objects is Array)
			{
				for each(var o in e.objects)
				{
					_deleteOneObject(o);
				}
			}
			else
			{
				_deleteOneObject(e.objects);
			}
		}
		private function _deleteOneObject(o)
		{
			if(o is Camera3D && o.name == SystemCamera)
			{
				ILogger.log('can not delete this camera',o)
				return;
			}
			
			if(o is LightBase)
			{
				var index = _lights.indexOf(o);
				
				if(index == -1)
					throw new Error();
				
				_lights.splice(index,1);
			}
			
			(o as ObjectContainer3D).parent.removeChild(o);
			
			_gcObjects.push(o);
		}
		
		private function newView3D()
		{
			var v:View3D = new View3D();
			v.antiAlias = 4;
			v.width = _app.stageWidth;
			v.height = _app.stageHeight;
			
			v.camera.name = Away3d.SystemCamera;
			v.scene.extra = new Object();
			v.scene.extra.ambientColor = 0x555555;
			//addView3D(v);
			_app.rootSprite.dispatchEvent(new NWEvent(NWEvent.CREATE_OBJECT,v));
		}
		
		private function onClearScene(e:NWEvent)
		{
			if(_view)
			{
				//
				for each(var c:ObjectContainer3D in _gcObjects)
				{
					c.dispose(true);
				}
				_gcObjects = [];
				
				//
				var children = [];
				var num = _view.scene.numChildren;
				for(var i = 0; i < num; ++i)
				{
					var c = _view.scene.getChildAt(i);
					children.push(c);
				}
				
				for each(var c:ObjectContainer3D in children)
				{
					c.dispose(true);
				}
				
				//
				removeView3D(view);
			}
			
			//
			//if(e.objects == NWEvent.CREATE_VIEW)
				//newView3D();
			
			//
			_lastObjs = null;
			
			//
			_lights = [];
		}
		
		private function onNewScene(e:NWEvent)
		{
			onClearScene(null);
			newView3D();
		}
		
		private var _lastObjs;
		private function onSelectObject(e:NWEvent)
		{
			//
			for each (var o in _lastObjs)
			{
				if(o is Entity)
				{
					(o as Entity).showBounds = false;
				}
			}
			
			
			//
			var objs;
			if(e.objects is Array)
			{
				objs = e.objects;
			}
			else
			{
				objs = [e.objects];
			}
			
			for each (var o in objs)
			{
				
				if(o is LightBase
				|| o is SkyBox)
				{
					
				}
				else if(o is Entity)
				{
					(o as Entity).showBounds = true;
				}
			}
			_lastObjs = objs;
		}
	}
}